<?php
namespace frontend\modules\Api\controllers;

use common\event\TallyEvent;
use common\models\StockRecord;
use common\models\Tally;
use common\models\TallyArap;
use common\models\TallyCategory;
use common\models\TallyPm;
use common\models\TallyRecord;
use common\services\TallyAccountService;
use common\services\TallyArapService;
use common\services\TallyFutureServices;
use common\services\TallyPmService;
use common\services\TallyRecordService;
use common\services\TallyService;
use common\services\TallyStockRecordService;
use common\services\ToolService;
use common\services\UserService;
use Yii;
use yii\base\Exception;
use yii\base\ExitException;
use yii\filters\AccessControl;
use yii\helpers\ArrayHelper;
use yii\base\DynamicModel;

/**
 * Class TallyRecordController
 * @package frontend\modules\Api\controllers
 * 账单明细管理
 */
class TallyRecordController extends ApiController
{
    /**
     * @return array
     * 引入行为验证 过滤授权
     */
    public function behaviors()
    {
        $config = [
            'access' => [
                'class' => AccessControl::className(),
                'denyCallback' => function($rule, $action){
                    return self::failureResponse(100001, '请先登录!',[]);
                },
                'rules' => [
                    [
                        'allow' => true,
                        'roles' => ['@'],
                    ]
                ]
            ],
        ];
        return ArrayHelper::merge(parent::behaviors(), $config);
    }

    /**
     * 重载初始化方案
     */
    public function init()
    {
        parent::init();
        // 注册监听事件
        $this->on(TallyEvent::RECORD_LOG_EVENT,['common\models\Tally','recordLog']);
    }

    /**
     * @throws
     * 账单明细记录 调用搜索
     */
    public function actionLists()
    {
        $condition = Yii::$app->request->get(); // type 等参数
        $tallyId = Yii::$app->getRequest()->get('tally_id');
        if(!$tallyId){
            return self::failureResponse(500,'账本id不能为空');
        }
        $this->checkRolePermission($this->_user['id'],$tallyId);
        $uid = TallyPmService::getRoleUid($this->_user['id'],$tallyId);
        // 默认取出当月
        /*if(!isset($condition['begin_date']) && !isset($condition['begin_date'])){
            $beginDate  = date('Y-m-01', strtotime(date("Y-m-d")));
            $endDate    = date('Y-m-d', strtotime("$beginDate +1 month -1 day"));
            $condition['begin_date'] = $beginDate;
            $condition['end_date']   = $endDate;
        }*/
        // 默认取出所有状态
        $list = TallyRecordService::getList($condition,$uid);
        $retData['data'] = [];
        $retData['pageInfo'] = [];
        // 遍历拼装附件数据
        foreach ($list['data'] as $lv) {
            $tmpData = $lv->toArray();
            $tmpData['attachment']  = $lv->attachment;
            $tmpData['type_txt']    = TallyRecord::getTypeTxt($lv['type']);
            $tmpData['state_txt']  = TallyRecord::getStatusTxt($lv['state']);
            $tmpData['amount_format']  = ToolService::moneyType($lv['amount']); //这是最帅的帅哥加的，如果成了，我就是大神
            $tmpData['uid_name'] = UserService::getUsernameByUid($lv['uid']);
            $tmpData['audit_name'] = UserService::getUsernameByUid($lv['audit_uid']);
            $retData['data'][] = $tmpData;
            
        }
        $retData['pageInfo'] = $list['pageInfo'];
        return self::successResponse($retData);
    }

    /**
     * 账单数据导出
     * @throws \yii\base\ExitException
     */
    public function actionExport()
    {
        $condition = Yii::$app->request->get(); // type 等参数
        $tallyId = Yii::$app->getRequest()->get('tally_id');
        if(!$tallyId){
            return self::failureResponse(500,'账本id不能为空');
        }
        $tallyInfo = TallyService::getOne($tallyId);
        if(!$tallyInfo){
            return self::failureResponse(500,'账本信息不能为空');
        }
        $this->checkRolePermission($this->_user['id'],$tallyId);
        // 默认取出所有状态 修改返回为data的bug
        $list = TallyRecordService::getAll($condition);
        // 遍历拼装附件数据
        $retData = [] ;
        foreach ($list as $lv) {
            if($lv['type'] == TallyRecord::TYPE_OUT) {
                $lv['amount'] = -1*$lv['amount'];
            }
            if($lv['type'] ==  TallyRecord::TYPE_TRANS) {
                $accountStr =  $lv['account_name'].'->'.$lv['account_dst_name'];
            }else{
                $accountStr = $lv['account_name'];
            }

            $one_category_name = $lv['category_ppname'] == '' ? $lv['category_pname'] : $lv['category_ppname'];
            $two_category_name = $lv['category_ppname'] == '' ? $lv['category_name'] : $lv['category_pname'];
            $three_category_name = $lv['category_ppname'] == '' ? '' : $lv['category_name'];

            $tmpData = [
                substr($lv['tally_time'],0,10)."\t",//账单时间
                TallyRecord::getTypeTxt($lv['type']),
                $one_category_name,
                $two_category_name,
                $three_category_name,
                $accountStr,
                $lv['amount'],
                ltrim($lv['project_name'].'-'.$lv['store_name'],'-'),
                $lv['member_name'],
                $lv['memo'],
                TallyRecord::getStatusTxt($lv['state']),
                TallyRecord::getTypeSourceTxt($lv),
                $lv['created_time'], //录入时间
            ];
            $retData[] = $tmpData;
        }
//        print_r($list);die;
        $filename = $tallyInfo['title'].'-'.date('YmdHis').'-'.rand(1000,9999).'.csv';
        ToolService::downLoadCsv($filename,[
            '账单日期',
            '类别',
            '一级分类',
            '二级分类',
            '三级分类',
            '账户',
            '金额',
            '客户/供应商',
            '员工',
            '备注',
            '状态',
            '来源',
            '录入时间',
        ],$retData);
        $filepath = Yii::$app->request->hostInfo.'/index/down-export?file='.$filename;
        return self::successResponse(['filepath'=>$filepath]);
    }

    /**
     * @throws \yii\base\ExitException
     * @desc 某一时间段内债务统计
     */
    public function actionCountDebt()
    {
        $condition = Yii::$app->request->get(); // type 等参数
        $tallyId = Yii::$app->getRequest()->get('tally_id');
        if(!$tallyId){
            return self::failureResponse(500,'账本id不能为空');
        }
        $this->checkRolePermission($this->_user['id'],$tallyId);
        // 默认取出当月
//        if(!isset($condition['begin_date']) && !isset($condition['begin_date'])){
//            $beginDate  = date('Y-m-01', strtotime(date("Y-m-d")));
//            $endDate    = date('Y-m-d', strtotime("$beginDate +1 month -1 day"));
//            $condition['begin_date'] = $beginDate;
//            $condition['end_date']   = $endDate;
//        }
        $uid = TallyPmService::getRoleUid($this->_user['id'],$tallyId);

        $retData  = TallyRecordService::countDebt($condition,$uid);
        $retData['in_format']  = ToolService::moneyType($retData['in']);
        $retData['out_format']  = ToolService::moneyType($retData['out']);
        $retData['debt_format']  = ToolService::moneyType($retData['debt']);
        $retData['check_format']  = ToolService::moneyType($retData['check']);
        return self::successResponse($retData);
    }
    /**
     * @throws \yii\base\ExitException
     * @desc 取出当月的
     */
    public function actionMonthDebt()
    {
        $condition = Yii::$app->request->get(); // type 等参数
        $tallyId = Yii::$app->getRequest()->get('tally_id');
        if(!$tallyId){
            return self::failureResponse(500,'账本id不能为空');
        }
        $this->checkRolePermission($this->_user['id'],$tallyId);
        // 默认取出当月
        $beginDate  = date('Y-m-01', strtotime(date("Y-m-d")));
        $endDate    = date('Y-m-d', strtotime("$beginDate +1 month -1 day"));
        $condition['begin_date'] = $beginDate;
        $condition['end_date']   = $endDate;
        $uid = TallyPmService::getRoleUid($this->_user['id'],$tallyId);

        $retData  = TallyRecordService::countDebt($condition,$uid);
        $retData['in_format']  = ToolService::moneyType($retData['in']);
        $retData['out_format']  = ToolService::moneyType($retData['out']);
        $retData['debt_format']  = ToolService::moneyType($retData['debt']);
        return self::successResponse($retData);
    }
    /**
     * @throws \yii\base\ExitException
     * @notes 账单详情
     */
    public function actionDetail()
    {
        $id = Yii::$app->getRequest()->get('id');
        if(!$id){
            return self::failureResponse(500,'账单id不能为空');
        }
//        $this->checkRolePermission($this->_user['id'],$id,'write');
        $result = TallyService::getOneByUid($id,$this->_user['id']);
        $info = $result->toArray();
        if(!empty($info)){
            $info['attachment']  = $result->attachment;
            $info['type_txt']    = TallyRecord::getTypeTxt($result['type']);
            $info['state_txt']  = TallyRecord::getStatusTxt($result['state']);
            $info['amount_format']  = ToolService::moneyType($result['amount']); //这是最帅的帅哥加的，如果成了，我就是大神
            $info['uid_name'] = UserService::getUsernameByUid($result['uid']);
            $info['audit_name'] = UserService::getUsernameByUid($result['audit_uid']);
        };



        return self::successResponse($info);
    }

    /**
     * @throws
     * 新增记账 不同类别处理不同参数 目前支持收入.支出
     */
    public function actionAdd()
    {
        $postData =  Yii::$app->getRequest()->post();
        $this->preventBrush('TallyRecordAdd',1);
        $form = DynamicModel::validateData([
            'tally_id'      => Yii::$app->getRequest()->post('tally_id'), //账本id
            'category_id'   => $postData['category_id'] ?: 0,//分类
            'arap_id'       => $postData['arap_id'] ?: 0,// 应收应付ID
            'future_id'       => $postData['future_id'] ?: 0,// 应收应付ID
            'account_id'    => $postData['account_id'] ?: 0, //账户
            'account_dst_id'  => $postData['account_dst_id'] ?: 0, //目标账户
            'amount'        => Yii::$app->getRequest()->post('amount'), // 金额
            'project_id'    => $postData['project_id'] ?: 0, // 项目
            'store_id'      => $postData['store_id'] ?: 0, // 商家
            'member_id'     => $postData['member_id'] ?: 0, // 成员
            'tally_time'    => Yii::$app->getRequest()->post('tally_time'), // 账单时间
            'is_gua'    => Yii::$app->getRequest()->post('is_gua',0), // 账单时间
            'is_yushou'    => Yii::$app->getRequest()->post('is_yushou',0), // 账单时间
            'uid'   => $this->_user['id'],
            'type'  => Yii::$app->getRequest()->post('type',10),
            'memo'  => Yii::$app->getRequest()->post('memo',''),
            'attachment'  => Yii::$app->getRequest()->post('attachment',''),//附件 多个逗号分隔
            'material_json'  => Yii::$app->getRequest()->post('material_json',''),//附件 多个逗号分隔
            'state' => 0, // 默认状态
        ],[
            [['tally_id','account_id','amount','tally_time','type'], 'required'],
            ['type', 'in', 'range' => [TallyRecord::TYPE_IN, TallyRecord::TYPE_OUT, TallyRecord::TYPE_TRANS]],
            ['memo', 'trim'],
        ]);
        if ($form->hasErrors()) {
            return self::failureResponse(500,current($form->getFirstErrors()));
        }
        if(!$form->account_dst_id) $form->account_dst_id = 0;
        if($form->type == TallyRecord::TYPE_TRANS) {
            if(!$form->account_id || !$form->account_dst_id) {
                return self::failureResponse(500,'新增失败.转账类型请选择账户');
            }
        }
        // 用户与账本权限角色关系
        $this->checkRolePermission($this->_user['id'],$form->tally_id,'write');
        $userRole = TallyPmService::getRole($form->uid,$form->tally_id) ;
        $form->state = TallyRecord::getDefaultStateByRole($userRole,$form->tally_id);
        if($form->state === null){
            return self::failureResponse(500,'请重新确认是否具有该账本操作权限！请刷新页面');
        }
        // 挂账操作 必须选择客户或者供应商
        if( !$form->arap_id && ($form->is_gua == 1 || $form->is_gua == true || in_array( $form->category_id, TallyCategory::$gzIds))) {
            if(!$form->store_id) {
                return self::failureResponse(500,'挂账操作必须选择客户或者供应商！');
            }

            // 执行挂账操作 不用统计金额 只需要入挂账库即可
            $result = TallyArapService::create(ArrayHelper::toArray($form));
            if(!$result){
                return self::failureResponse(500,'新增失败.'.TallyArapService::getError());
            }else{
                return self::successResponse(['id'=>$result]);
            }
        }




        // 开启事务
        $connection = Yii::$app->db->beginTransaction();
        try{
            $result = TallyRecordService::create(ArrayHelper::toArray($form));
            if(!$result){
                throw new Exception(TallyService::getError());
            }
            // 这里对状态进行拦截 只有状态正常的才要进入账户金额统计
            if( $form->state == TallyRecord::STATE_VALID){
                TallyRecordService::calRelationAmount($form);
                // 如果涉及挂账操作 进行挂账金额重新核算
                if($form->arap_id) {
                    TallyArapService::calRelationAmount($form->arap_id);
                }
            }
            //添加预收表格数据
            if(!$form->future_id && $form->is_yushou){
                $formData = ArrayHelper::toArray($form);
                $formData['tally_record_id'] = $result;
                $result = TallyFutureServices::create($formData);
                if(!$result){
                    throw new Exception(TallyService::getError());
                }
            }
            $connection->commit();
            // 触发账单记录事件
            $this->triggerEvents([
                'tally_id' => $form->tally_id,
                'uid'   => $form->uid,
                'type'  => 2,
                'content' => '添加账单,id:'.$result.',金额:'.$form->amount,
            ]);
            return self::successResponse(['id'=>$result]);
        }catch (\Exception $ex){
            $connection->rollBack();
            return self::failureResponse(500,'新增失败.'.$ex->getMessage());
        }
    }

    /**
     * @throws
     * 账单修改
     */
    public function actionEdit()
    {
        $postData =  Yii::$app->getRequest()->post();
        // 允许修改的项目
        $form = DynamicModel::validateData([
            'id'    => $postData['id'],
            'memo'  => $postData['memo'] ?: '',
            'category_id' => $postData['category_id'] ?: 0,
            'arap_id'   => $postData['arap_id'] ?: 0,// 应收应付ID
            'member_id' => $postData['member_id'] ?: 0,
            'store_id' => $postData['store_id'] ?: 0,
            'project_id' => $postData['project_id'] ?: 0,
            'is_gua' => Yii::$app->getRequest()->post('is_gua','0'),
            'account_id'    => $postData['account_id'] ?: 0, //账户
            'account_dst_id' => $postData['account_dst_id'] ?: 0, //目标账户
            'amount'        => Yii::$app->getRequest()->post('amount'), // 金额
            'attachment'  => Yii::$app->getRequest()->post('attachment',''),//附件 多个逗号分隔
            'material_json'  => Yii::$app->getRequest()->post('material_json',''),//附件 多个逗号分隔
            'tally_time'    => Yii::$app->getRequest()->post('tally_time'), // 账单时间
            'uid' => $this->_user['id']
        ],[
            [['id','category_id','account_id','amount','tally_time'], 'required'],
            [['category_id', 'account_id','account_dst_id', 'project_id', 'store_id', 'member_id'], 'integer'],
            ['memo', 'trim'],
        ]);
        if ($form->hasErrors()) {
            return self::failureResponse(500,current($form->getFirstErrors().'----'));
        }
        $tallyId = ArrayHelper::getValue($postData,'tally_id','');
        if(!$tallyId){
            return self::failureResponse(500,'账本信息无法识别');
        }
        $formArr = ArrayHelper::toArray($form);
        // 检查用户的账本操作权限
        $this->checkRolePermission($this->_user['id'],$tallyId,'write');
        // 挂账操作 必须选择客户或者供应商
        if( !$form->arap_id && (in_array( $form->category_id, TallyCategory::$gzIds) || $form->is_gua == 1 || $form->is_gua == true )) {
            if(!$form->store_id) {
                return self::failureResponse(500,'挂账操作必须选择客户或者供应商！');
            }
            // 审核状态还原
            $userRole = TallyPmService::getRole($this->_user['id'],$tallyId) ;
            $formArr['state'] = TallyArap::getDefaultStateByRole($userRole);//重置默认状态
            $result = TallyArapService::update([
                'id'    => $form->id,
                'tally_id' => $tallyId,
            ],$formArr);
            if(!$result){
                return self::failureResponse(500,'更新失败.'.TallyArapService::getError());
            }else{
                return self::successResponse();
            }
        }
        // 每次编辑都会重置账单的状态为角色操作的默认状态
        $userRole = TallyPmService::getRole($this->_user['id'],$tallyId) ;
        $formArr['state'] = TallyRecord::getDefaultStateByRole($userRole,$tallyId);//重置默认状态
        $result = TallyRecordService::update([
            'id'    => $form->id,
            'tally_id' => $tallyId,
//            'uid'   => $this->_user['id'], //协作账目无法编辑会出问题
        ],$formArr);
        if($result){
            return self::successResponse();
        }else{
            return self::failureResponse(500,'更新失败.'.TallyService::getError());
        }
    }

    /**
     * @throws
     * 删除账单
     */
    public function actionDel()
    {
        $id = Yii::$app->getRequest()->post('id');
        if(!$id){
            return self::failureResponse(500,'记录Id不能为空');
        }
        try{
            $result = TallyRecordService::delete([
                'id'    => $id,
                'uid'   => $this->_user['id']
            ]);
            if($result){
                return self::successResponse();
            }else{
                return self::failureResponse(500,'删除失败.'.TallyService::getError());
            }
        }catch (\Exception $e) {
            return self::failureResponse(500,'删除失败.'.$e->getMessage());

        }
    }

    /**
     * @throws \yii\base\ExitException
     * @desc 账单审核
     */
    public function actionAudit()
    {
        $id = Yii::$app->getRequest()->post('id');
        if(!$id){
            return self::failureResponse(500,'账单Id不能为空');
        }
        $memo = Yii::$app->getRequest()->post('memo','');
        $state = Yii::$app->getRequest()->post('state');
        if(!in_array($state,[TallyRecord::STATE_REFUSED,TallyRecord::STATE_VALID])){
            return self::failureResponse(500,'状态参数校验失败');
        }
        // 获取账单数据
        $tallyRecord = TallyRecord::find()->where([
            'id' => $id,
        ])->one();
        if(!$tallyRecord) {
            return self::failureResponse(500,'账单数据不存在');
        }
        // 用户与账本权限角色关系
        $this->checkRolePermission($this->_user['id'],$tallyRecord->tally_id,'audit');
        // 更新账单状态 // 开启事务
        $connection = Yii::$app->db->beginTransaction();
        try{
            $tallyRecord->state =$state;
            $tallyRecord->audit_uid =$this->_user['id'];
            $tallyRecord->audit_time = date('Y-m-d H:i:s');
            $result = $tallyRecord->save();
            if(!$result) {
                throw new Exception('状态更新失败');
            }
            // 只有审核通过的才会进行核算账户金额  账单状态从0到1 从0到-1的本身就没做记录
            if($state == TallyRecord::STATE_VALID){
                TallyRecordService::calRelationAmount($tallyRecord);
                if($tallyRecord->arap_id) {
                    TallyArapService::calRelationAmount($tallyRecord->arap_id); // 应收应付统计核算
                }
                // 进销存相关 操作遍历商品进行出入库管理
                if($tallyRecord->stock_id) {
                    TallyStockRecordService::handleProductFlow($tallyRecord->stock_id,$tallyRecord->id);
                }
            }else {
                // 账单审核拒绝 同时标记库存单状态
                if($tallyRecord->stock_id) {
                    TallyStockRecordService::updateSate([
                        'id' => $tallyRecord->stock_id
                    ],StockRecord::STATE_REFUSED);
                }
            }
            $connection->commit();
            // 触发账单记录事件
            $this->triggerEvents([
                'tally_id' => $tallyRecord->tally_id,
                'uid'   => $this->_user['id'],
                'type'  => 2,
                'content' => '审核账单,id:'.$id.',意见:'.TallyRecord::getStatusTxt($state).',备注:'.$memo,
            ]);
            return self::successResponse();
        }catch (\Exception $ex){
            $connection->rollBack();
            return self::failureResponse(500,'新增失败.'.$ex->getMessage());
        }
    }

}
